package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.RabbitMqConfig;
import net.xdclass.enums.*;
import net.xdclass.exception.BizException;
import net.xdclass.feign.ProductOrderFeignService;
import net.xdclass.interceptor.LoginInterceptor;
import net.xdclass.mapper.CouponRecordMapper;
import net.xdclass.mapper.CouponTaskMapper;
import net.xdclass.model.*;
import net.xdclass.request.LockCouponRecordRequest;
import net.xdclass.service.CouponRecordService;
import net.xdclass.util.JsonData;
import net.xdclass.vo.CouponRecordVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 二当家小D
 * @since 2021-05-19
 */
@Service
@Slf4j
public class CouponRecordServiceImpl implements CouponRecordService {
    @Autowired
    private CouponRecordMapper couponRecordMapper;

    @Autowired
    private CouponTaskMapper couponTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMqConfig rabbitMqConfig;

    @Autowired
    private ProductOrderFeignService productOrderFeignService;

    @Override
    public Map<String,Object> page(int page, int size) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        Page<CouponRecordDO> pageInfo = new Page<>(page, size);
        IPage<CouponRecordDO> ipage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecordDO>()
                .eq("user_id", loginUser.getId())
                .orderByDesc("create_time"));
        Map<String, Object> pageMap = new HashMap<>();
        pageMap.put("total_record", ipage.getTotal());
        pageMap.put("total_page", ipage.getPages());
        pageMap.put("current_data", ipage.getRecords().stream().map(obj->(
             beanProcess(obj)
        )).collect(Collectors.toList()));
        return pageMap;
    }

    @Override
    public CouponRecordVO getDetail(long recordId) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        CouponRecordDO couponRecordDO = couponRecordMapper.selectOne(new QueryWrapper<CouponRecordDO>().eq("user_id", loginUser.getId()).eq("id", recordId));
        if(couponRecordDO==null){
            return null;
        }
        return beanProcess(couponRecordDO);
    }

    /**
     * 锁优惠券
     * 1 修改优惠券状态
     * 2 插入优惠券任务
     * 3 将信息插入消息队列
     * @param lockCouponRecordRequest
     * @return
     */
    @Override
    public JsonData lockCouponRecord(LockCouponRecordRequest lockCouponRecordRequest) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        List<Long> lockCouponRecordIds = lockCouponRecordRequest.getLockCouponRecordIds();
        String orderOutTradeNo = lockCouponRecordRequest.getOrderOutTradeNo();
        //修改优惠券状态
        int updateRows = couponRecordMapper.updateCouponRecord(loginUser.getId(), lockCouponRecordIds, CouponStateEnum.USED.name());
        List<CouponTaskDO> couponTaskList = lockCouponRecordIds.stream().map(obj -> {
            CouponTaskDO couponTaskDO = new CouponTaskDO();
            couponTaskDO.setCreateTime(new Date());
            couponTaskDO.setLockState(StockStateEnum.LOCK.name());
            couponTaskDO.setOutTradeNo(orderOutTradeNo);
            couponTaskDO.setCouponRecordId(obj);
            return couponTaskDO;
        }).collect(Collectors.toList());
        int insertRows = couponTaskMapper.insertBatch(couponTaskList);
        if (lockCouponRecordIds.size() == insertRows && insertRows == updateRows) {
            //发送延迟消息
            for (CouponTaskDO couponTaskDO : couponTaskList) {
                CouponRecordMessage couponRecordMessage = new CouponRecordMessage();
                couponRecordMessage.setTaskId(couponTaskDO.getId());
                couponRecordMessage.setOutTradeNo(couponTaskDO.getOutTradeNo());
                rabbitTemplate.convertAndSend(rabbitMqConfig.getEventExchange(), rabbitMqConfig.getCouponReleaseDelayRoutingKey(), couponRecordMessage);
                log.info("优惠券锁定信息发送成功：{}",couponRecordMessage.toString());
            }
            return JsonData.buildSuccess();
        } else {
            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }
    }

    /**
     * 解锁优惠券记录
     * 1 查询task工作单是否存在
     * 2 查询订单状态
     *
     * @param couponRecordMessage
     * @return
     */
    @Override
    @Transactional
    public boolean releaseCouponRecord(CouponRecordMessage couponRecordMessage) {
        //查询task工作单是否存在
        CouponTaskDO couponTaskDO = couponTaskMapper.selectOne(new QueryWrapper<CouponTaskDO>().eq("id", couponRecordMessage.getTaskId()));
        if (couponTaskDO == null) {
            log.warn("工作单不存在,消息{}",couponRecordMessage);
            return true;
        }
        //lock状态才处理
        if (couponTaskDO.getLockState().equalsIgnoreCase(StockStateEnum.LOCK.name())) {

            //查询订单状态
            JsonData jsonData = productOrderFeignService.queryProductOrderState(couponRecordMessage.getOutTradeNo());
            if (jsonData.getCode() == 0) {
                //正常响应 判断订单状态
                String state = jsonData.getData().toString();
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
                    //状态为new，需要返回false 让消息重新返回到消息队列
                    log.warn("订单状态为new，返回给消息队列重新投递，消息={}",couponRecordMessage);
                    return false;
                }
                //如果是已经支付了
                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    //修改task状态为finish
                    couponTaskDO.setLockState(StockStateEnum.FINISH.name());
                    couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", couponRecordMessage.getTaskId()));
                    log.info("订单已经支付，修改库存锁定工作单FINISH状态:{}",couponRecordMessage);
                    return true;
                }
            }
            //订单不存在，或者订单被取消，确认消息，修改task状态为CANCEL,恢复优惠券使用记录为NEW
            log.warn("订单不存在，或者订单被取消，确认消息，修改task状态为CANCEL,恢复优惠券使用记录为NEW,message={}",couponRecordMessage);
            couponTaskDO.setLockState(StockStateEnum.CANCEL.name());
            couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", couponRecordMessage.getTaskId()));
            //恢复优惠券使用记录为NEW
            couponRecordMapper.updateState(couponTaskDO.getCouponRecordId(),ProductOrderStateEnum.NEW.name());
            return true;
        } else {
            log.warn("工作单状态不是lock,state={},消息体={}",couponTaskDO.getLockState(),couponRecordMessage);
            return true;
        }
    }

    private CouponRecordVO beanProcess(CouponRecordDO couponRecordDO){
        CouponRecordVO couponRecordVO = new CouponRecordVO();
        BeanUtils.copyProperties(couponRecordDO,couponRecordVO);
        return couponRecordVO;
    }
}
